*&---------------------------------------------------------------------*
*& Report ZEX_LISTING_93                                               *
*&---------------------------------------------------------------------*
*& Created By: James Wood (james.wood@bowdarkconsulting.com)           *
*& Created On: 12/12/2008                                              *
*& Purpose:    This program shows how to create an ABAP Unit test in   *
*&             a report program.                                       *
*&---------------------------------------------------------------------*
REPORT zex_listing_93.

*----------------------------------------------------------------------*
*       CLASS lcx_insufficient_funds  DEFINITION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcx_insufficient_funds DEFINITION
      INHERITING FROM cx_static_check.
ENDCLASS.                    "lcx_insufficient_funds  DEFINITION

*----------------------------------------------------------------------*
*       CLASS lcl_account DEFINITION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_account DEFINITION.

  PUBLIC SECTION.
    DATA: account_id TYPE numc5 READ-ONLY,
          balance TYPE bapicurr_d READ-ONLY.

    METHODS:
      constructor IMPORTING im_acct_id TYPE numc5,

      deposit     IMPORTING im_amount TYPE bapicurr_d,

      withdrawal  IMPORTING im_amount TYPE bapicurr_d
                    RAISING lcx_insufficient_funds,

      transfer    IMPORTING im_amount     TYPE bapicurr_d
                            im_to_account TYPE REF
                                            TO lcl_account
                    RAISING lcx_insufficient_funds.

ENDCLASS.                    "lcl_account DEFINITION

*----------------------------------------------------------------------*
*       CLASS lcl_account IMPLEMENTATION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_account IMPLEMENTATION.

  METHOD constructor.
    account_id = im_acct_id.
  ENDMETHOD.                    "constructor

  METHOD deposit.
    balance = balance + im_amount.
  ENDMETHOD.                    "deposit

  METHOD withdrawal.
    IF balance LT im_amount.
      RAISE EXCEPTION TYPE lcx_insufficient_funds.
    ENDIF.
    balance = balance - im_amount.
  ENDMETHOD.                    "withdrawal

  METHOD transfer.
    IF balance LT im_amount.
      RAISE EXCEPTION TYPE lcx_insufficient_funds.
    ENDIF.
    im_to_account->deposit( im_amount ).
  ENDMETHOD.                    "transfer

ENDCLASS.                    "lcl_account IMPLEMENTATION

*----------------------------------------------------------------------*
* START-OF-SELECTION Event Module                                      *
*----------------------------------------------------------------------*
START-OF-SELECTION.
  PERFORM transfer_funds.

*&---------------------------------------------------------------------*
*&      Form  transfer_funds
*&---------------------------------------------------------------------*
*       text
*----------------------------------------------------------------------*
FORM transfer_funds.

* Local Data Declarations:
  DATA: lr_checking TYPE REF TO lcl_account,
        lr_savings  TYPE REF TO lcl_account.

* Create checking account #10000 with an opening balance of $1500.00:
  CREATE OBJECT lr_checking
    EXPORTING
      im_acct_id = '10000'.
  lr_checking->deposit( '1500.00' ).

* Create savings account #20000 with an opening balance of $500.00:
  CREATE OBJECT lr_savings
    EXPORTING
      im_acct_id = '20000'.
  lr_savings->deposit( '500.00' ).

* Try to transfer $1000.00 from checking to savings:
  TRY.
    CALL METHOD lr_checking->transfer
      EXPORTING
        im_amount     = '1000.00'
        im_to_account = lr_savings.

*   Question: Without ABAP Unit, how would you know if this operation
*             failed under normal circumstances after a code change?
    WRITE: / 'Transfer performed successfully.'.
  CATCH lcx_insufficient_funds.
    WRITE: / 'Insufficient funds to transfer...'.
  ENDTRY.

ENDFORM.                    "transfer_funds

*----------------------------------------------------------------------*
*       CLASS lcl_account_test DEFINITION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_account_test DEFINITION  "#AU Risk_Level Harmless
                      FOR TESTING. "#AU Duration Short

  PRIVATE SECTION.
    DATA: lr_checking TYPE REF TO lcl_account,
          lr_savings  TYPE REF TO lcl_account.

    METHODS:
      setup,
      test_transfer FOR TESTING,
      teardown.

ENDCLASS.                    "lcl_account_test DEFINITION

*----------------------------------------------------------------------*
*       CLASS lcl_account_test IMPLEMENTATION
*----------------------------------------------------------------------*
*
*----------------------------------------------------------------------*
CLASS lcl_account_test IMPLEMENTATION.

  METHOD setup.
*   Create checking account #10000 with an opening balance of $1500.00:
    CREATE OBJECT lr_checking
      EXPORTING
        im_acct_id = '10000'.
    lr_checking->deposit( '1500.00' ).

*   Create savings account #20000 with an opening balance of $500.00:
    CREATE OBJECT lr_savings
      EXPORTING
        im_acct_id = '20000'.
    lr_savings->deposit( '500.00' ).

  ENDMETHOD.                    "setup

  METHOD test_transfer.
*   Try to transfer $1000.00 from checking to savings:
    TRY.
      CALL METHOD lr_checking->transfer
        EXPORTING
          im_amount     = '1000.00'
          im_to_account = lr_savings.
    CATCH lcx_insufficient_funds.
      CALL METHOD cl_aunit_assert=>fail
        EXPORTING
            msg = 'Insufficient funds...'.
    ENDTRY.

*   Make sure the savings account has a balance of $1500.00:
    CALL METHOD cl_aunit_assert=>assert_equals
      EXPORTING
        act = lr_savings->balance
        exp = '1500.00'
        msg = 'Savings account not credited correctly.'.

*   Make sure the checking account has a balance of $500.00:
    CALL METHOD cl_aunit_assert=>assert_equals
      EXPORTING
        act = lr_checking->balance
        exp = '500.00'
        msg = 'Checking account not debited correctly.'.
  ENDMETHOD.                    "test_transfer

  METHOD teardown.
    CLEAR: lr_checking, lr_savings.
  ENDMETHOD.                    "teardown

ENDCLASS.                    "lcl_account_test IMPLEMENTATION